package com.ylfstu.set_;

import java.util.HashSet;

public class HashSetSource {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add("java");//到此位置，第 1 次 add 分析完毕.
        hashSet.add("php");//到此位置，第 2 次 add 分析完毕
        hashSet.add("java");
        System.out.println("set=" + hashSet);

        /*
        1.执行HashSet()构造器，return HashMap<>();

        2.执行add()
            public boolean add(E e) {
                return map.put(e, PRESENT)==null;
            }
        3.执行map.put(),该方法会执行hash(key) 得到key对应的hash值 算法：(h = key.hashCode()) ^ (h >>> 16)
            public V put(K key, V value) {
                return putVal(hash(key), key, value, false, true);
            }
        4.执行putVal(key)
            final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
                Node<K,V>[] tab; Node<K,V> p; int n, i;
                //如果当前table是null 或者 大小=0，就进行第一次扩容，扩容到16个空间
                if ((tab = table) == null || (n = tab.length) == 0)
                    n = (tab = resize()).length;

                //1.根据key，得到的hash，去计算该key应该存放到table表的哪个索引位置，
                //并把这个位置的对象赋给辅助变量p
                //2.判断p 是否为null
                //2.1如果p 为null， 表示还没有存放元素，就创建一个Node(key="java", value=PRESENT)
                if ((p = tab[i = (n - 1) & hash]) == null)
                    tab[i] = newNode(hash, key, value, null);
                else {
                    Node<K,V> e; K k;
                    //如果当前索引位置对应的链表的第一个元素和准备添加的key的hash值一样
                    //并且满足 下列两个条件之一：
                    //1.准备加入的key 和 p 指向的Node 结点的 key 是同一个对象
                    //2.p 指向的Node 结点的 key 的equals() 和准备加入的key比较后相同
                    //就不能加入
                    if (p.hash == hash &&
                        ((k = p.key) == key || (key != null && key.equals(k))))
                        e = p;
                    //再判断 p 是不是一颗红黑树
                    //如果是红黑树，就调用 putTreeVal() 进行添加
                    else if (p instanceof TreeNode)
                        e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
                    else {//如果tab对应的索引位置，已经是一个链表，就使用for循环比较
                          //(1)依次和该链表的每一个元素比较后，都不相同，则加入到该链表的最后
                          //   注意把元素添加到链表后，立即判断 该链表是否已经达到8个结点
                          //   达到了，就调用treeifyBin()对当前这个列表进行树化(红黑树)
                          //   注意，在转成红黑树时再进行一个判断，
                                if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY(64))
                                    resize();
                          // 如果上面条件成立，先 table 扩容.
                          // 只有上面条件不成立时，才进行转成红黑
                          //(2)依次和该链表的每一个元素比较过程中，如果有相同情况，就直接break
                        for (int binCount = 0; ; ++binCount) {
                            if ((e = p.next) == null) {
                                p.next = newNode(hash, key, value, null);
                                if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                                    treeifyBin(tab, hash);
                                break;
                            }
                            if (e.hash == hash &&
                                ((k = e.key) == key || (key != null && key.equals(k))))
                                break;
                            p = e;
                        }
                    }
                    if (e != null) { // existing mapping for key
                        V oldValue = e.value;
                        if (!onlyIfAbsent || oldValue == null)
                            e.value = value;
                        afterNodeAccess(e);
                        return oldValue;
                    }
                }
                ++modCount;
                //只要向table加了一个元素，size就++
                if (++size > threshold)
                    resize();
                afterNodeInsertion(evict);
                return null;
            }

        */
    }
}
